package middleware

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"net"
	"net/http"
	"private-domain-overseas-service/pkg/common"
	"private-domain-overseas-service/pkg/result"
	"private-domain-overseas-service/pkg/status/bizadmin"
	"private-domain-overseas-service/pkg/xerr"
	"private-domain-overseas-service/tools/ent"
	"private-domain-overseas-service/tools/ent/adminrouter"
	"private-domain-overseas-service/tools/ent/adminuser"
	"strings"
)

type CheckAndRecordLogMiddleware struct {
	Orm *ent.Client
}

func NewCheckAndRecordLogMiddleware(orm *ent.Client) *CheckAndRecordLogMiddleware {
	return &CheckAndRecordLogMiddleware{
		orm,
	}
}

func (m *CheckAndRecordLogMiddleware) Handle(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 查询用户账号
		userId := common.JwtAdminAuthUserId(r.Context())
		user, err := m.Orm.AdminUser.Query().
			Where(adminuser.IDEQ(int(userId))).
			Where(adminuser.IsDeleteEQ(bizadmin.NotDelete)).
			First(r.Context())
		if err != nil || user == nil {
			result.HttpResult(r, w, nil, xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("查询用户失败： %v", err)))
			return
		}

		headerMap := r.Header
		// 查列表不记录日志
		if strings.Contains(headerMap.Get("X-Button-Key"), ":list") {
			next(w, r)
			return
		}

		// 接口地址
		url := r.URL.Path

		// 定义额外信息
		var extraInfo string
		body, _ := io.ReadAll(r.Body)
		defer r.Body.Close()
		// 缓存一次，给defer调用
		r.Body = io.NopCloser(bytes.NewReader(body))
		if len(body) > 4096 {
			body = body[:4096]
		}
		if strings.Contains(r.URL.Path, "/upload/file") {
			extraInfo = "上传文件"
		} else {
			extraInfo = string(body)
		}

		// ip
		ip, _ := handleGetIP(r)

		// 操作系统
		var os string
		userAgent := headerMap.Get("User-Agent")
		start := strings.Index(userAgent, "(")
		end := strings.Index(userAgent, ")")
		if start >= 0 && end > start {
			os = userAgent[start+1 : end]
		}

		// 查询页面
		var pageStr string
		page, _ := m.Orm.AdminRouter.Query().
			Where(adminrouter.AdminRouterRouteNameEQ(headerMap.Get("X-Button-Key"))).
			Where(adminrouter.IsDeleteEQ(bizadmin.NotDelete)).
			Where(adminrouter.AdminRouterMenuTypeEQ(bizadmin.TypeButton)).
			First(r.Context())
		if page != nil {
			pageStr = page.AdminRouterMenuName
		}

		// 记录日志
		err = m.Orm.AdminLog.Create().
			SetAdminLogAccount(user.AdminUserUsername).
			SetAdminLogIP(ip).
			SetAdminLogOperateSystem(os).
			SetAdminLogPage(pageStr).
			SetAdminLogURL(url).
			SetAdminLogBrowser(headerMap.Get("User-Agent")).
			SetAdminLogExtraInfo(extraInfo).
			Exec(r.Context())
		if err != nil {
			result.HttpResult(r, w, nil, xerr.ErrCodeMsg(xerr.ServerOperationExceptionError, fmt.Sprintf("创建日志失败: %v", err)))
			return
		}
		next(w, r)
	}
}

// handleGetIP - 获取IP
func handleGetIP(r *http.Request) (string, error) {
	ip := r.Header.Get("X-Real-IP")
	if net.ParseIP(ip) != nil {
		return ip, nil
	}

	ip = r.Header.Get("X-Forward-For")
	for _, i := range strings.Split(ip, ",") {
		if net.ParseIP(i) != nil {
			return i, nil
		}
	}

	// 最可靠的ip获取方式
	ip, _, err := net.SplitHostPort(r.RemoteAddr)
	if err != nil {
		return "", err
	}

	if net.ParseIP(ip) != nil {
		return ip, nil
	}

	return "", errors.New("no valid ip found")
}
